using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;

using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;

namespace WL.Think.Abp.Entities;

/// <summary>
/// 实体基类
/// </summary>
[Serializable]
public abstract class BaseEntity<TKey> : FullAuditedAggregateRoot<TKey>, IMultiTenant where TKey: struct, IComparable<TKey>
{
    /// <summary>
    /// 无参实体,提供给子类进行无参构造使用
    /// </summary>
    protected BaseEntity()
    {
        /*
         当包含导航属性列表时，在更新或者新增时，如果主键没有复制，那么就会出现多个相同值的主键，这个时候EFCore更新到数据库时，
         会发现跟踪了多个同一主键值的实体，因此会报下面错误：
         The instance of entity type 'x' cannot be tracked because another instance with the key value '{Id: x}' is already being tracked. 
         When attaching existing entities, ensure that only one entity instance with a given key value is attached.
         */
        GenerateId();
    }

    /// <summary>
    /// 实体初始化
    /// </summary>
    /// <param name="id">主键ID</param>
    /// <param name="tenantId">租户ID</param>
    protected BaseEntity(TKey id, Guid? tenantId = null) : base(id)
    {
        Id = id;
        TenantId = tenantId;
        ConcurrencyStamp = Guid.NewGuid().ToString("N");
    }

    [Key]
    [Comment("主键")]
    public virtual new TKey Id { get => base.Id;  set => base.Id = value; }

    /// <summary>
    /// 租户ID
    /// </summary>
    [Comment("租户ID")]
    public virtual Guid? TenantId {  get; set; }

    /// <summary>
    /// 内置数据表示
    /// </summary>
    [Comment("内置数据")]
    public virtual bool Builtin { get; set; }

    /// <summary>
    /// 并发时间戳
    /// </summary>
    [ConcurrencyCheck]
    [Comment("并发令牌")]
    public override string ConcurrencyStamp { get; set; }

    /// <summary>
    /// 设置主键 
    /// </summary>
    /// <param name="id"></param>
    public void SetId(TKey id)
    {
        Id = id;
    }

    /// <summary>
    /// 生成一个主键ID
    /// </summary>
    public virtual void GenerateId()
    {

    }

    /// <summary>
    /// 重置主键值
    /// </summary>
    public virtual void ResetId()
    {
        Id = default;
    }

    /// <summary>
    /// 重置实体
    /// </summary>
    public virtual void Reset()
    {
        ResetId();
        RefreshConcurrencyStamp();
        TenantId = null;
        CreatorId = null;
        CreationTime = DateTime.Now;
        LastModifierId = null;
        LastModificationTime = null;
        DeleterId = null;
        DeletionTime = null;
        ExtraProperties = new ExtraPropertyDictionary();
    }

    /// <summary>
    /// 刷新并发令牌
    /// </summary>
    public virtual void RefreshConcurrencyStamp()
    {
        ConcurrencyStamp = Guid.NewGuid().ToString("N");
    }

    
}

/// <summary>
/// 实体基类
/// </summary>
[Serializable]
public abstract class BaseEntity : BaseEntity<Guid>
{
    /// <summary>
    /// 无参实体,提供给子类进行无参构造使用
    /// </summary>
    protected BaseEntity()
    {
       
    }

    /// <summary>
    /// 实体初始化
    /// </summary>
    /// <param name="id">主键ID</param>
    /// <param name="tenantId">租户ID</param>
    protected BaseEntity(Guid id, Guid? tenantId = null) : base(id, tenantId)
    {

    }

    public override void ResetId()
    {
        SetId(Guid.Empty);
    }

    public override void GenerateId()
    {
        SetId(Guid.NewGuid());
    }
}
